package com.example;

import com.example.draw.DrawShape;
import com.example.draw.DrawShapeFactory;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.shape.StrokeType;

/**
 * <p>遮罩管理</p>
 *
 * @author dc
 * @date 2025-09-16
 **/
public class MaskManager {
    private final PaneManager paneManager;
    private Rectangle selectionRect;
    private Rectangle topMask, bottomMask, leftMask, rightMask;
    private AnchorPane maskPane;
    private static final Color MASK_COLOR = Color.color(0, 0, 0, 0.5);

    // 添加角点相关字段
    private Group cornerGroup;
    private Circle topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner;
    private static final double CORNER_RADIUS = 4.0; // 角点半径
    private static final Color CORNER_COLOR = Color.WHITE; // 角点颜色
    
    private double selectionOriginX = 0;
    private double selectionOriginY = 0;
    private double selectionOriginWidth = 0;
    private double selectionOriginHeight = 0;
    private double adjustStartX = 0;
    private double adjustStartY = 0;
    int stretchableGap = 6;
    
    private Shape newShape;

    public MaskManager(PaneManager paneManager) {
        this.paneManager = paneManager;
        initializeMasks();
    }

    public AnchorPane getMaskPane() {
        return maskPane;
    }
    public Rectangle getSelectionRect() {
        return selectionRect;
    }
    public Group getCornerGroup() {
        return cornerGroup;
    }

    /**
     * 初始化遮罩组件
     */
    private void initializeMasks() {
        // 创建一个父布局
        this.maskPane = new AnchorPane();
        // 设置遮罩大小为全屏，即锚点距离四边为0
        AnchorPane.setTopAnchor(maskPane, 0.0);
        AnchorPane.setBottomAnchor(maskPane, 0.0);
        AnchorPane.setLeftAnchor(maskPane, 0.0);
        AnchorPane.setRightAnchor(maskPane, 0.0);

        topMask = new Rectangle();
        bottomMask = new Rectangle();
        leftMask = new Rectangle();
        rightMask = new Rectangle();

        topMask.setFill(MASK_COLOR);
        bottomMask.setFill(MASK_COLOR);
        leftMask.setFill(MASK_COLOR);
        rightMask.setFill(MASK_COLOR);
        
        maskPane.getChildren().addAll(topMask, bottomMask, leftMask, rightMask);

        selectionRect = new Rectangle();
        // 设置选择区域矩形
        selectionRect.setStroke(Color.ROYALBLUE); // 设置边框颜色
        selectionRect.setStrokeWidth(2); // 设置边框宽度
        selectionRect.setStrokeType(StrokeType.OUTSIDE); // 设置边框类型为外接边框，在选择范围外
        selectionRect.setFill(Color.TRANSPARENT); // 设置填充颜色
        selectionRect.setOnMouseMoved(event -> {
            if (CaptureProperty.isDrawing) {
                return;
            }
            Cursor cursor = null;
            if (isWithInDraggableArea(event.getX(), event.getY())) {
                cursor = Cursor.MOVE;
            } else if (isWithInRbResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.SE_RESIZE;
            } else if (isWithInLtResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.NW_RESIZE;
            } else if (isWithInRtResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.NE_RESIZE;
            } else if (isWithInLbResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.SW_RESIZE;
            } else if (isWithInRhResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.E_RESIZE;
            } else if (isWithInLhResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.W_RESIZE;
            } else if (isWithInTvResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.N_RESIZE;
            } else if (isWithInBvResizableArea(event.getX(), event.getY())) {
                cursor = Cursor.S_RESIZE;
            }
            selectionRect.setCursor(cursor);
        });
        selectionRect.setOnMousePressed(event -> {
            System.out.println("select鼠标按下:"+event.getX()+","+event.getY());
            if (CaptureProperty.isDrawing) {
                DrawShape drawShape = paneManager.getToolbarManager().getSelectedShape();
                // 创建一个新实例
                newShape = DrawShapeFactory.createShape(drawShape);
                paneManager.getDrawStackManager().addShape(newShape);
            }
            // 记录鼠标按下位置
            adjustStartX = event.getX();
            adjustStartY = event.getY();
            // 记录选择区域起始位置
            selectionOriginX = selectionRect.getX();
            selectionOriginY = selectionRect.getY();
            // 记录选择区域起始长宽
            selectionOriginWidth = selectionRect.getWidth();
            selectionOriginHeight = selectionRect.getHeight();
        });
        selectionRect.setOnMouseDragged(event -> {
            if (CaptureProperty.isDrawing) {
                DrawShape drawShape = (DrawShape)newShape;
                drawShape.updateShape(selectionRect, adjustStartX, adjustStartY, event.getX(), event.getY());
                return;
            }
            // 鼠标当前位置只能用于计算拖动过程的位移，不能设为选择区域的基点坐标，否则会造成区域位置偏移
            double currentX = event.getX();
            double currentY = event.getY();
            // 鼠标移动距离
            double dx = currentX - adjustStartX;
            double dy = currentY - adjustStartY;
            double newX = selectionOriginX;
            double newY = selectionOriginY;
            double newWidth = selectionOriginWidth;
            double newHeight = selectionOriginHeight;
            // 选择区域移动
            if (selectionRect.getCursor() == Cursor.MOVE) {
                newX = selectionOriginX + dx;
                newY = selectionOriginY + dy;
                if (newX < 0) {
                    newX = 0;
                } else if (newX + selectionRect.getWidth() > CaptureProperty.screenWidth) {
                    newX = CaptureProperty.screenWidth - selectionRect.getWidth();
                }
                if (newY < 0) {
                    newY = 0;
                } else if (newY + selectionRect.getHeight() > CaptureProperty.screenHeight) {
                    newY = CaptureProperty.screenHeight - selectionRect.getHeight();
                }
            } 
            // 右下角拖动
            else if (selectionRect.getCursor() == Cursor.SE_RESIZE) {
                // 以左上角为原点
                // 计算右下角坐标
                double rbX = Math.abs(selectionOriginX + selectionOriginWidth + dx);
                double rbY = Math.abs(selectionOriginY + selectionOriginHeight + dy);
                // 右下点与左上点争抢选择区域基点，谁的坐标小，谁为基点
                newX = Math.min(rbX, selectionOriginX);
                newY = Math.min(rbY, selectionOriginY);
                newWidth = Math.abs(selectionOriginWidth + dx);
                newHeight = Math.abs(selectionOriginHeight + dy);
            }
            // 左上角拖动
            else if (selectionRect.getCursor() == Cursor.NW_RESIZE) { 
                // 以右下角为原点
                // 计算左上角坐标
                double ltX = Math.abs(selectionOriginX + dx);
                double ltY = Math.abs(selectionOriginY + dy);
                // 左上点与右下点争抢选择区域基点，谁的坐标小，谁为基点
                newX = Math.min(ltX, selectionOriginX + selectionOriginWidth);
                newY = Math.min(ltY, selectionOriginY + selectionOriginHeight);
                newWidth = Math.abs(selectionOriginWidth - dx);
                newHeight = Math.abs(selectionOriginHeight - dy);
            }
            // 右上角拖动
            else if (selectionRect.getCursor() == Cursor.NE_RESIZE) {
                // 以左下角为原点
                // 获取右上角坐标
                double rtX = Math.abs(selectionOriginX + selectionOriginWidth + dx);
                double rtY = Math.abs(selectionOriginY + dy);
                // 右上点与左下点争抢选择区域基点，谁的坐标小，谁为基点
                newX = Math.min(rtX, selectionOriginX);
                newY = Math.min(rtY, selectionOriginY + selectionOriginHeight);
                newWidth = Math.abs(selectionOriginWidth + dx);
                newHeight = Math.abs(selectionOriginHeight - dy);
            } 
            // 左下角拖动
            else if (selectionRect.getCursor() == Cursor.SW_RESIZE) {
                // 以右上角为原点
                // 获取左下角坐标
                double lbX = Math.abs(selectionOriginX + dx);
                double lbY = Math.abs(selectionOriginY + selectionOriginHeight + dy);
                // 左下点与右上点争抢选择区域基点，谁的坐标小，谁为基点
                newX = Math.min(lbX, selectionOriginX + selectionOriginWidth);
                newY = Math.min(lbY, selectionOriginY);
                newWidth = Math.abs(selectionOriginWidth - dx);
                newHeight = Math.abs(selectionOriginHeight + dy);
            }
            // 右侧拖动
            else if (selectionRect.getCursor() == Cursor.E_RESIZE) { 
                // 计算右边X坐标
                double rX = Math.abs(selectionOriginX + selectionOriginWidth + dx);
                newX = Math.min(rX, selectionOriginX);
                newWidth = Math.abs(selectionOriginWidth + dx);
            }
            // 左侧拖动
            else if (selectionRect.getCursor() == Cursor.W_RESIZE) {
                // 计算左边X坐标
                double lx = Math.abs(selectionOriginX + dx);
                newX = Math.min(lx, selectionOriginX + selectionOriginWidth);
                newWidth = Math.abs(selectionOriginWidth - dx);
            }
            // 上侧拖动
            else if (selectionRect.getCursor() == Cursor.N_RESIZE) {
                // 获取上侧Y坐标
                double tY = Math.abs(selectionOriginY + dy);
                newY = Math.min(tY, selectionOriginY + selectionOriginHeight);
                newHeight = Math.abs(selectionOriginHeight - dy);
            } 
            // 底部拖动
            else if (selectionRect.getCursor() == Cursor.S_RESIZE) {
                // 获取下侧Y坐标
                double bY = Math.abs(selectionOriginY + selectionOriginHeight + dy);
                newY = Math.min(bY, selectionOriginY);
                newHeight = Math.abs(selectionOriginHeight + dy);
            }
            updateMaskWithHole(newX, newY, newWidth, newHeight);
            paneManager.getToolbarManager().showToolbar(newX, newY, newWidth, newHeight);
        });
        
        selectionRect.setOnMouseEntered(event -> { 
            if (!CaptureProperty.isDrawing) {
                return;
            }
            // 鼠标进入，设置鼠标样式为十字
            selectionRect.setCursor(Cursor.CROSSHAIR);
        });
        selectionRect.setOnMouseReleased(event -> {
            // 更新画图布局的位置
            paneManager.getDrawStackManager().changeStackPosition(selectionRect.getX(), selectionRect.getY(), selectionRect.getWidth(), selectionRect.getHeight());
            if (CaptureProperty.isDrawing) {
                return;
            }
        });
        
        // 初始化四个角点
        cornerGroup = new Group();
        topLeftCorner = new Circle();
        topRightCorner = new Circle();
        bottomLeftCorner = new Circle();
        bottomRightCorner = new Circle();
        cornerGroup.getChildren().addAll(topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner);
        // 不拦截鼠标事件，让鼠标事件继续往下传递到选中区域
        cornerGroup.setMouseTransparent(true);

        // 设置角点样式
        Circle[] corners = {topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner};
        for (Circle corner : corners) {
            corner.setRadius(CORNER_RADIUS);
            corner.setFill(CORNER_COLOR);
            corner.setStroke(Color.ROYALBLUE);
            corner.setStrokeWidth(1);
            corner.setVisible(false);
        }
    }

    /**
     * 更新遮罩层，复用已有元素提高性能<br>
     * 矩形遮罩的坐标和宽高都是相对于屏幕左上角
     * @param x 矩形左上点的x坐标
     * @param y 矩形左上点的y坐标
     * @param width 矩形的宽度
     * @param height 矩形的高度
     */
    public void updateMaskWithHole(double x, double y, double width, double height) {
        // 设置选择矩形的起始位置和大小
        selectionRect.setX(x);
        selectionRect.setY(y);
        selectionRect.setWidth(width);
        selectionRect.setHeight(height);
        selectionRect.setVisible(true);
        
        // 更新四个遮罩矩形的位置和大小，大小于判断是处理边框在屏幕边界上的情况，边框处于屏幕边界时只需要更少的遮罩

        // 下方遮罩，未框选时会占满屏幕
        // 将下方遮罩的更新放在最前面并去掉遮罩的隐藏是为了当鼠标按下时避免空洞闪烁的情况，
        // 空洞闪烁的原因是鼠标按下时，其它遮罩元素会先隐藏，导致大面积空洞，然后再被下方遮罩覆盖全屏，这样会产生闪烁
        bottomMask.setX(0);
        bottomMask.setY(y + height);
        bottomMask.setWidth(CaptureProperty.screenWidth);
        bottomMask.setHeight(CaptureProperty.screenHeight - (y + height));
        bottomMask.setVisible(true);

        // 上方遮罩
        topMask.setX(0);
        topMask.setY(0);
        topMask.setWidth(CaptureProperty.screenWidth);
        topMask.setHeight(y);
        topMask.setVisible(true);

        // 左方遮罩
        leftMask.setX(0);
        leftMask.setY(y);
        leftMask.setWidth(x);
        leftMask.setHeight(height);
        leftMask.setVisible(true);

        // 右方遮罩
        rightMask.setX(x + width);
        rightMask.setY(y);
        rightMask.setWidth(CaptureProperty.screenWidth - (x + width));
        rightMask.setHeight(height);
        rightMask.setVisible(true);

        // 更新四个角点的位置
        updateCornerPositions(x, y, width, height);
    }

    /**
     * 更新四个角点的位置
     * @param x 选择区域x坐标
     * @param y 选择区域y坐标
     * @param width 选择区域宽度
     * @param height 选择区域高度
     */
    private void updateCornerPositions(double x, double y, double width, double height) {
        // 左上角点
        topLeftCorner.setCenterX(x);
        topLeftCorner.setCenterY(y);
        topLeftCorner.setVisible(true);

        // 右上角点
        topRightCorner.setCenterX(x + width);
        topRightCorner.setCenterY(y);
        topRightCorner.setVisible(true);

        // 左下角点
        bottomLeftCorner.setCenterX(x);
        bottomLeftCorner.setCenterY(y + height);
        bottomLeftCorner.setVisible(true);

        // 右下角点
        bottomRightCorner.setCenterX(x + width);
        bottomRightCorner.setCenterY(y + height);
        bottomRightCorner.setVisible(true);
    }
    /**
     * 判断鼠标是否在可拖动区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拖动区域
     */
    private boolean isWithInDraggableArea(double x, double y) {
        double selectionX = selectionRect.getX();
        double selectionY = selectionRect.getY();
        double selectionWidth = selectionRect.getWidth();
        double selectionHeight = selectionRect.getHeight();
        
        double draggableX = selectionX + stretchableGap;
        double draggableY = selectionY + stretchableGap;
        double draggableWidth = selectionWidth - stretchableGap * 2;
        double draggableHeight = selectionHeight - stretchableGap * 2;
        
        return  (x >= draggableX && x <= draggableX + draggableWidth && y >= draggableY && y <= draggableY + draggableHeight);
    }
    /**
     * 判断鼠标是否在右下角可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInRbResizableArea(double x, double y) { 
        double rbX = selectionRect.getX() + selectionRect.getWidth() - stretchableGap;
        double rbY = selectionRect.getY() + selectionRect.getHeight() - stretchableGap;
        
        return (!isWithInDraggableArea(x, y) && (x >= rbX && x <= rbX + stretchableGap && y >= rbY && y <= rbY + stretchableGap));
    }

    /**
     * 判断鼠标是否在右上角可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInRtResizableArea(double x, double y) { 
        double rtX = selectionRect.getX() + selectionRect.getWidth() - stretchableGap;
        double rtY = selectionRect.getY();
        
        return (!isWithInDraggableArea(x, y) && (x >= rtX && x <= rtX + stretchableGap && y >= rtY && y <= rtY + stretchableGap));
    }
    /**
     * 判断鼠标是否在左下角可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInLbResizableArea(double x, double y) { 
        double lbX = selectionRect.getX();
        double lbY = selectionRect.getY() + selectionRect.getHeight() - stretchableGap;
        
        return (!isWithInDraggableArea(x, y) && (x >= lbX && x <= lbX + stretchableGap && y >= lbY && y <= lbY + stretchableGap));
    }
    /**
     * 判断鼠标是否在左上角可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInLtResizableArea(double x, double y) { 
        double ltX = selectionRect.getX();
        double ltY = selectionRect.getY();
        
        return (!isWithInDraggableArea(x, y) && (x >= ltX && x <= ltX + stretchableGap && y >= ltY && y <= ltY + stretchableGap));
    }
    /**
     * 判断鼠标是否在右边横向可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInRhResizableArea(double x, double y) {
        double rightVerticalX = selectionRect.getX() + selectionRect.getWidth() - stretchableGap;
        double rightVerticalY = selectionRect.getY() + stretchableGap;
        double horizontalHeight = selectionRect.getHeight() - stretchableGap * 2;
        return (!isWithInDraggableArea(x, y) && (x >= rightVerticalX && x <= rightVerticalX + stretchableGap && y >= rightVerticalY && y <= rightVerticalY + horizontalHeight));
    }
    /**
     * 判断鼠标是否在左边横向可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInLhResizableArea(double x, double y) {
        double leftVerticalX = selectionRect.getX();
        double leftVerticalY = selectionRect.getY() + stretchableGap;
        double horizontalHeight = selectionRect.getHeight() - stretchableGap * 2;
        return (!isWithInDraggableArea(x, y) && (x >= leftVerticalX && x <= leftVerticalX + stretchableGap && y >= leftVerticalY && y <= leftVerticalY + horizontalHeight));
    }
    /**
     * 判断鼠标是否在上方纵向可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInTvResizableArea(double x, double y) { 
        double topHorizontalX = selectionRect.getX() + stretchableGap;
        double topHorizontalY = selectionRect.getY();
        double horizontalWidth = selectionRect.getWidth() - stretchableGap * 2;
        return (!isWithInDraggableArea(x, y) && (x >= topHorizontalX && x <= topHorizontalX + horizontalWidth && y >= topHorizontalY && y <= topHorizontalY + stretchableGap));
    }
    /**
     * 判断鼠标是否在下方纵向可拉伸区域
     * @param x 鼠标x坐标
     * @param y 鼠标y坐标
     * @return 是否在可拉伸区域
     */
    private boolean isWithInBvResizableArea(double x, double y) { 
        double bottomHorizontalX = selectionRect.getX() + stretchableGap;
        double bottomHorizontalY = selectionRect.getY() + selectionRect.getHeight() - stretchableGap;
        double horizontalWidth = selectionRect.getWidth() - stretchableGap * 2;
        return (!isWithInDraggableArea(x, y) && (x >= bottomHorizontalX && x <= bottomHorizontalX + horizontalWidth && y >= bottomHorizontalY && y <= bottomHorizontalY + stretchableGap));
    }
    
}
